{% extends "base.html" %}

{% block title %}WebDAV 修复 - Alist-MikananiRss WebUI{% endblock %}

{% block content %}
<div class="fade-in">
    <div class="page-header border-bottom pt-3 pb-2 mb-3">
        <div class="d-flex flex-column flex-md-row align-items-md-center justify-content-between gap-2">
            <div>
                <h1 class="h2 mb-0">
                    <i class="bi bi-lightning-charge me-2"></i>
                    WebDAV 手动修复
                </h1>
                <p class="text-muted small mb-0">针对指定目录执行一次性的嵌套目录修复任务</p>
            </div>
            <div class="d-flex gap-2 flex-md-row flex-column w-100 w-md-auto">
                <button type="button" class="btn btn-outline-secondary" onclick="loadManualDefaults()">
                    <i class="bi bi-arrow-clockwise me-2"></i>
                    重新加载默认设置
                </button>
            </div>
        </div>
    </div>

    <div class="row g-3">
        <div class="col-12 col-xl-8">
            <div class="card">
                <div class="card-header">
                    <h5 class="card-title mb-0">
                        <i class="bi bi-gear me-2"></i>
                        执行参数
                    </h5>
                </div>
                <div class="card-body">
                    <form id="manualFixForm" class="row g-3">
                        <div class="col-12">
                            <label for="manualTargetPath" class="form-label">目标目录</label>
                            <input type="text" class="form-control" id="manualTargetPath" placeholder="/115/TV/示例目录">
                            <div class="form-text">支持绝对或相对路径，留空时将使用默认修复路径或下载目录。</div>
                        </div>

                        <div class="col-md-6">
                            <div class="form-check form-switch">
                                <input class="form-check-input" type="checkbox" id="manualExecuteMode">
                                <label class="form-check-label" for="manualExecuteMode">实际执行</label>
                                <div class="form-text">关闭时为预览模式，仅输出将执行的操作，不进行文件移动。</div>
                            </div>
                        </div>
                        <div class="col-md-6">
                            <div class="form-check form-switch">
                                <input class="form-check-input" type="checkbox" id="manualRecursiveScan">
                                <label class="form-check-label" for="manualRecursiveScan">递归扫描</label>
                                <div class="form-text">启用后会扫描目标目录下的所有子目录。</div>
                            </div>
                        </div>

                        <div class="col-md-6">
                            <label for="manualConflictStrategy" class="form-label">冲突策略</label>
                            <select class="form-select" id="manualConflictStrategy">
                                <option value="skip">跳过</option>
                                <option value="rename">重命名</option>
                                <option value="overwrite">覆盖</option>
                            </select>
                            <div class="form-text">当目标位置已存在同名文件时的处理方式。</div>
                        </div>
                    </form>

                    <div class="d-flex gap-2 mt-4">
                        <button type="button" class="btn btn-primary" id="runManualFixButton" onclick="triggerManualFix()">
                            <i class="bi bi-play-circle me-2"></i>
                            执行手动修复
                        </button>
                        <button type="button" class="btn btn-success" onclick="saveManualDefaults()">
                            <i class="bi bi-save me-2"></i>
                            保存为默认
                        </button>
                        <button type="button" class="btn btn-outline-secondary" onclick="resetManualForm()">
                            <i class="bi bi-arrow-counterclockwise me-2"></i>
                            重置
                        </button>
                    </div>
                </div>
            </div>
        </div>

        <div class="col-12 col-xl-4">
            <div class="card h-100">
                <div class="card-header">
                    <h5 class="card-title mb-0">
                        <i class="bi bi-clipboard-data me-2"></i>
                        执行结果
                    </h5>
                </div>
                <div class="card-body" id="manualFixResult">
                    <div class="text-center text-muted">
                        <i class="bi bi-inbox fs-1"></i>
                        <p class="mt-2 mb-0">暂未执行任务</p>
                    </div>
                </div>
            </div>
        </div>
    </div>
</div>
{% endblock %}

{% block extra_js %}
<script>
    let manualDefaults = {
        default_path: '',
        execute_mode: false,
        recursive_scan: true,
        conflict_strategy: 'skip',
    };
    let currentJobId = null;
    let jobPollTimer = null;

    document.addEventListener('DOMContentLoaded', function() {
        setActiveNav('webdav');
        loadManualDefaults();
    });

    async function loadManualDefaults() {
        try {
            const config = await apiCall('/api/admin/config/current');
            const webdavManual = config?.webdav?.manual || {};

            manualDefaults = {
                default_path: webdavManual.default_path || '',
                execute_mode: !!webdavManual.execute_mode,
                recursive_scan: webdavManual.recursive_scan !== undefined ? !!webdavManual.recursive_scan : true,
                conflict_strategy: webdavManual.conflict_strategy || 'skip',
            };

            applyManualDefaults();
            showNotification('默认参数已更新', 'success');
        } catch (error) {
            console.error('加载默认参数失败:', error);
            showNotification('加载默认参数失败: ' + error.message, 'danger');
        }
    }

    function collectManualConfig() {
        const rawPath = document.getElementById('manualTargetPath').value.trim();
        return {
            default_path: rawPath || (manualDefaults.default_path ? manualDefaults.default_path : null),
            execute_mode: document.getElementById('manualExecuteMode').checked,
            recursive_scan: document.getElementById('manualRecursiveScan').checked,
            conflict_strategy: document.getElementById('manualConflictStrategy').value,
        };
    }

    function applyManualDefaults() {
        document.getElementById('manualTargetPath').value = manualDefaults.default_path || '';
        document.getElementById('manualExecuteMode').checked = manualDefaults.execute_mode;
        document.getElementById('manualRecursiveScan').checked = manualDefaults.recursive_scan;
        document.getElementById('manualConflictStrategy').value = manualDefaults.conflict_strategy;
    }

    function resetManualForm() {
        applyManualDefaults();
        stopJobPolling();
        currentJobId = null;
        document.getElementById('manualFixResult').innerHTML = `
            <div class="text-center text-muted">
                <i class="bi bi-inbox fs-1"></i>
                <p class="mt-2 mb-0">暂未执行任务</p>
            </div>
        `;
    }

    async function persistManualDefaults({ silent = false } = {}) {
        const manualConfig = collectManualConfig();
        const payload = {
            webdav: {
                manual: {
                    default_path: manualConfig.default_path,
                    execute_mode: manualConfig.execute_mode,
                    recursive_scan: manualConfig.recursive_scan,
                    conflict_strategy: manualConfig.conflict_strategy,
                }
            }
        };

        try {
            await apiCall('/api/admin/config/save', {
                method: 'POST',
                body: JSON.stringify(payload),
            });

            manualDefaults = {
                default_path: manualConfig.default_path || '',
                execute_mode: manualConfig.execute_mode,
                recursive_scan: manualConfig.recursive_scan,
                conflict_strategy: manualConfig.conflict_strategy,
            };

            if (!silent) {
                showNotification('默认参数已保存', 'success');
            }
        } catch (error) {
            console.error('保存默认参数失败:', error);
            if (!silent) {
                showNotification('保存默认参数失败: ' + error.message, 'danger');
            }
            throw error;
        }
    }

    async function saveManualDefaults() {
        try {
            await persistManualDefaults({ silent: false });
        } catch (error) {
            // 已在 persistManualDefaults 中处理通知
        }
    }

    async function triggerManualFix() {
        const button = document.getElementById('runManualFixButton');
        const path = document.getElementById('manualTargetPath').value.trim();
        const executeMode = document.getElementById('manualExecuteMode').checked;
        const recursiveScan = document.getElementById('manualRecursiveScan').checked;
        const conflictStrategy = document.getElementById('manualConflictStrategy').value;

        button.disabled = true;
        button.innerHTML = '<span class="spinner-border spinner-border-sm me-2" role="status"></span>执行中...';

        try {
            await persistManualDefaults({ silent: true });

            const payload = {
                path: path || null,
                execute_mode: executeMode,
                recursive_scan: recursiveScan,
                conflict_strategy: conflictStrategy,
            };

            const response = await apiCall('/api/admin/webdav/manual-fix', {
                method: 'POST',
                body: JSON.stringify(payload),
            });

            currentJobId = response.job_id;
            renderJobStatus(response);
            startJobPolling();
            showNotification(response.message || '手动修复任务已创建', 'success');
        } catch (error) {
            console.error('执行手动修复失败:', error);
            renderJobError(error.message);
            showNotification('手动修复失败: ' + error.message, 'danger');
        } finally {
            button.disabled = false;
            button.innerHTML = '<i class="bi bi-play-circle me-2"></i>执行手动修复';
        }
    }

    function escapeHtml(value) {
        if (typeof value !== 'string') {
            return value;
        }
        return value
            .replace(/&/g, '&amp;')
            .replace(/</g, '&lt;')
            .replace(/>/g, '&gt;')
            .replace(/"/g, '&quot;')
            .replace(/'/g, '&#39;');
    }

    function formatManualDetailItem(item) {
        if (item === null || item === undefined) {
            return '';
        }
        if (typeof item === 'string') {
            return escapeHtml(item);
        }
        if (Array.isArray(item)) {
            return item.map(formatManualDetailItem).filter(Boolean).join('<br>');
        }

        const statusClassMap = {
            success: 'bg-success',
            skipped: 'bg-warning text-dark',
            error: 'bg-danger',
            pending: 'bg-secondary',
        };
        const statusLabelMap = {
            success: '成功',
            skipped: '跳过',
            error: '错误',
            pending: '等待',
        };

        const parts = [];

        if (item.status) {
            const badgeClass = statusClassMap[item.status] || 'bg-secondary';
            const badgeLabel = statusLabelMap[item.status] || escapeHtml(String(item.status));
            parts.push(`<span class="badge ${badgeClass} me-2">${badgeLabel}</span>`);
        }

        const lines = [];
        if (item.directory) {
            lines.push(`目录: ${escapeHtml(String(item.directory))}`);
        }
        if (item.file) {
            lines.push(`文件: ${escapeHtml(String(item.file))}`);
        }
        if (item.new_name) {
            lines.push(`新名称: ${escapeHtml(String(item.new_name))}`);
        }
        if (typeof item.size_mb === 'number') {
            lines.push(`大小: ${item.size_mb.toFixed(2)} MB`);
        }
        if (item.message) {
            lines.push(`信息: ${escapeHtml(String(item.message))}`);
        }

        const lineHtml = lines.length ? `<div>${lines.join('<br>')}</div>` : '';

        if (!parts.length && !lineHtml) {
            return escapeHtml(JSON.stringify(item));
        }

        return `${parts.join('')}${lineHtml}`;
    }

    function startJobPolling() {
        stopJobPolling();
        if (!currentJobId) {
            return;
        }
        jobPollTimer = setInterval(fetchJobStatus, 2000);
        fetchJobStatus();
    }

    async function fetchJobStatus() {
        if (!currentJobId) {
            return;
        }
        try {
            const job = await apiCall(`/api/admin/webdav/jobs/${encodeURIComponent(currentJobId)}`);
            renderJobStatus(job);
            if (job.status === 'completed' || job.status === 'failed') {
                stopJobPolling();
            }
        } catch (error) {
            showNotification('查询任务状态失败: ' + error.message, 'warning');
        }
    }

    function stopJobPolling() {
        if (jobPollTimer) {
            clearInterval(jobPollTimer);
            jobPollTimer = null;
        }
    }

    function renderJobStatus(job) {
        const container = document.getElementById('manualFixResult');
        if (!container) {
            return;
        }

        const statusMap = {
            queued: { class: 'bg-secondary', label: '排队中' },
            running: { class: 'bg-info', label: '运行中' },
            completed: { class: 'bg-success', label: '已完成' },
            failed: { class: 'bg-danger', label: '失败' },
        };
        const badge = statusMap[job.status] || statusMap.queued;
        const options = job.options || {};
        const result = job.result || {};

        let detailsHtml = '';
        if (Array.isArray(result.details) && result.details.length) {
            detailsHtml += '<h6 class="mt-3">处理明细</h6><ul class="list-group list-group-flush">';
            result.details.forEach(item => {
                const content = formatManualDetailItem(item);
                detailsHtml += `<li class="list-group-item">${content}</li>`;
            });
            detailsHtml += '</ul>';
        }

        if (Array.isArray(result.errors) && result.errors.length) {
            detailsHtml += '<div class="alert alert-danger mt-3" role="alert">';
            detailsHtml += '<h6 class="alert-heading">错误详情</h6><ul class="mb-0">';
            result.errors.forEach(err => {
                detailsHtml += `<li>${escapeHtml(err)}</li>`;
            });
            detailsHtml += '</ul></div>';
        }

        container.innerHTML = `
            <div class="d-flex justify-content-between align-items-center mb-3">
                <div>
                    <span class="badge ${badge.class}">${badge.label}</span>
                    <span class="ms-2 text-muted">Job ID: ${job.job_id || 'N/A'}</span>
                </div>
                <span class="text-muted">${job.finished_at || job.started_at || job.created_at || ''}</span>
            </div>
            <ul class="list-unstyled mb-0">
                <li><strong>目标目录:</strong> ${job.target_dir || 'N/A'}</li>
                <li><strong>模式:</strong> ${job.dry_run ? '预览（未执行）' : '实际执行'}</li>
                <li><strong>递归扫描:</strong> ${options.recursive_scan ? '是' : '否'}</li>
                <li><strong>冲突策略:</strong> ${options.conflict_strategy || 'skip'}</li>
            </ul>
            <hr>
            <div class="row text-center">
                <div class="col-6 col-sm-3">
                    <div class="fs-4 fw-bold">${result.total_found ?? 0}</div>
                    <div class="text-muted">发现项</div>
                </div>
                <div class="col-6 col-sm-3">
                    <div class="fs-4 fw-bold text-success">${result.success_count ?? 0}</div>
                    <div class="text-muted">已处理</div>
                </div>
                <div class="col-6 col-sm-3">
                    <div class="fs-4 fw-bold text-warning">${result.skip_count ?? 0}</div>
                    <div class="text-muted">跳过</div>
                </div>
                <div class="col-6 col-sm-3">
                    <div class="fs-4 fw-bold text-danger">${result.error_count ?? 0}</div>
                    <div class="text-muted">错误</div>
                </div>
            </div>
            ${detailsHtml}
            ${job.error ? `<div class="alert alert-danger mt-3 mb-0">${escapeHtml(job.error)}</div>` : ''}
        `;
    }

    function renderJobError(message) {
        const container = document.getElementById('manualFixResult');
        if (!container) {
            return;
        }
        container.innerHTML = `
            <div class="alert alert-danger">
                <i class="bi bi-x-circle me-2"></i>
                手动修复失败: ${escapeHtml(message)}
            </div>
        `;
    }

    window.addEventListener('beforeunload', function() {
        stopJobPolling();
    });
</script>
{% endblock %}
